﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;

namespace DevOnServer
{
    public class CNetwork
    {
        public void setWaitingTime(int time)
        {
            m_selectTime = (time % 1000) * 1000;
        }

        public bool run()
        {
            int doneClients = 0;

            m_fdSet.Clear();

            int i, c, b = 0;

            CNetConnection conn;

            for (i = 0, c = m_connections.Count; i < c; ++i)
            {
                if (m_connections[i].Connected)
                {
                    m_fdSet.Add(m_connections[i].Socket);
                    doneClients++;
                }

                if (doneClients == 64 ||
                    (doneClients > 0 &&
                    i + 1 == c))
                {
                    try
                    {
                        Socket.Select(m_fdSet, null, null, m_selectTime);
                    }
                    catch (Exception e)
                    {
                        CConsole.WriteLine("Socket select error: {0}", e.Message);
                        return false;
                    }

                    doneClients = 0;

                    while (b <= i)
                    {
                        conn = m_connections[b];

                        if (m_fdSet.Contains(conn.Socket))
                        {
                            if (conn is CNetAcceptor)
                            {
                                CNetClient newClient = new CNetClient();

                                newClient.Socket = conn.Socket.Accept();

                                newClient.Connected = true;
                                newClient.IP = (newClient.Socket.RemoteEndPoint as IPEndPoint).Address.ToString();
                                newClient.Port = (newClient.Socket.RemoteEndPoint as IPEndPoint).Port;

                                m_connections.Add(newClient);
                                (conn as CNetAcceptor).NewClients.Enqueue(newClient);
                            }
                            else if (conn is CNetClient)
                            {
                                if (!(conn as CNetClient).receive())
                                    conn.close();
                            }
                        }

                        ++b;
                    }

                    m_fdSet.Clear();
                }
            }

            for (i = m_connections.Count - 1; i >= 0; --i)
            {
                if (m_connections[i].Free)
                {
                    m_connections[i].Dispose();
                    m_connections.RemoveAt(i);
                }
            }

            return true;
        }

        public CNetAcceptor createAcceptor(int port)
        {
            CNetAcceptor newAcceptor = new CNetAcceptor();
            if (newAcceptor.bind(port))
            {
                m_connections.Add(newAcceptor);
                return newAcceptor;
            }
            else
                return null;
        }

        private int m_selectTime;

        private List<Socket> m_fdSet = new List<Socket>();

        private List<CNetConnection> m_connections = new List<CNetConnection>();
    }
}